package com.adee.juc;

import com.adee.util.Utils;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * 使用AQS自己实现一个不可重入锁
 *
 */
public class Test006_MyLockByAQS {
    public static void main(String[] args) {
        // 测试自定义非可重入锁，实现一个生产者消费者模式
        List<String> list = new ArrayList<>();  // 最多5个元素
        MyLock lock = new MyLock();
        Condition notEmpty = lock.newCondition();
        Condition notFull = lock.newCondition();
        Runnable producer = ()->{
            for (;;) {
                lock.lock();
                try {
                    if (list.size() >= 5) {
                        try {
                            notFull.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } else {
                        String str = UUID.randomUUID().toString();
                        System.out.println("produce===>>> " + str);
                        Utils.sleep(1);
                        list.add(str);  // 队尾入
                        notEmpty.signal();
                    }
                }finally {
                    lock.unlock();
                }
            }
        };
        Runnable consumer = ()->{
            for(;;) {
                lock.lock();
                try {
                    if(list.size() == 0) {
                        try {
                            notEmpty.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } else {
                        String str = list.remove(0);  // 队首出
                        System.out.println(Thread.currentThread().getName() + "<<<=== " + str);
                        notFull.signal();
                    }
                }finally {
                    lock.unlock();
                }
            }
        };
        // 3个消费者，1个生产者
        new Thread(consumer, "consumer-1").start();
        new Thread(consumer, "consumer-2").start();
        new Thread(consumer, "consumer-3").start();
        new Thread(producer, "producer-1").start();
    }

}

/**
 * 自定义锁实现Lock接口
 */
class MyLock implements Lock {
    // 聚合AQS
    private final Sync sync = new Sync();

    @Override
    public void lock() {
        sync.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(time));
    }

    @Override
    public void unlock() {
        sync.release(1);
    }

    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }

    /**
     * 继承AQS类需要重写5个方法：
     * tryAcquire
     * tryRelease
     * tryAcquireShared  // 独占锁用不到该方法，可不重写
     * tryReleaseShared  // 独占锁用不到该方法，可不重写
     * isHeldExclusively
     * newCondition
     *
     */
    static class Sync extends AbstractQueuedSynchronizer {
        /**
         * 独占获取锁
         * @param arg
         * @return
         */
        @Override
        protected boolean tryAcquire(int arg) {
            // 判断重入，快速失败
            if(Thread.currentThread() == getExclusiveOwnerThread() && getState() >= 1) {
                throw new RuntimeException("lock is not reentrant");
            }
            if(compareAndSetState(0,1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        /**
         * 独占释放锁
         * @param arg
         * @return
         */
        @Override
        protected boolean tryRelease(int arg) {
            if(Thread.currentThread() != getExclusiveOwnerThread()) {
                throw new IllegalMonitorStateException("current state can only tryRelase by " +
                        "owner Thread, owner thread is " +
                        getExclusiveOwnerThread().getName() +
                        ", current thread is " + Thread.currentThread().getName());
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        /**
         * 共享获取锁
         * @param arg
         * @return
         */
        @Override
        protected int tryAcquireShared(int arg) {
            return super.tryAcquireShared(arg);
        }

        /**
         * 共享释放锁
         * @param arg
         * @return
         */
        @Override
        protected boolean tryReleaseShared(int arg) {
            return super.tryReleaseShared(arg);
        }

        /**
         * 当前锁是否被独占式持有
         * @return
         */
        @Override
        protected boolean isHeldExclusively() {
            return getState()==1;
        }

        // ConditionObject是AQS的实例内部类，必须先有一个AQS实例，然后才能创建一个ConditionObject对象
        protected Condition newCondition() {
            return this.new ConditionObject();
        }
    }
}